/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.issue.model;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.internna.iwebjtracker.project.model.IWebJTrackerUser;
import org.internna.iwebjtracker.project.model.Module;
import org.internna.iwebjtracker.project.model.Project;
import org.internna.iwebjtracker.project.model.Version;
import org.internna.iwebjtracker.project.validation.Errors;
import org.internna.iwebmvc.model.Document;
import org.internna.iwebmvc.model.MultiDocument;

/**
 * Represents a ticket with a request from a user to the project development team.
 *
 * @author Jose Noheda
 * @since 1.0
 */
public interface Issue<M extends Module<P, M>, V extends Version<U, P, V>, U extends IWebJTrackerUser, P extends Project<?, M, V, U, P>, C extends Comment<U, C, I>, I extends Issue<M, V, U, P, C, I>> {

    /**
     * Types of links between issues.
     */
    enum Link {
        DEPENDANT, DUPLICATE, RELATED, SUBTASK;
    }

    /**
     * Type of tickets a user can open.
     */
    enum Type {
        BUG, ENHANCEMENT, FEEDBACK, TASK;
    }

    /**
     * Valid flow that any issue can traverse.
     */
    enum Status {
        ASSIGNED, CLOSED, OPEN, WORK_IN_PROGRESS;
    }

    /**
     * Valid end states once an issue has been closed.
     */
    enum ResolutionStatus {
        DUPLICATE, FIXED, INVALID, NOT_REPRODUCIBLE, PENDING, VERIFIED, WONT_FIX;
    }

    /**
     * Importance the issue has in the user's opinion.
     */
    enum Severity {
        TRIVIAL, MINOR, FIX, CRITICAL, BLOCKER;
    }

    /**
     * The user that reported this issue.
     *
     * @return a not null user
     */
    U getCreator();

    /**
     * Usually the current logged user. Implementations may limit updates on this field.
     *
     * @param creator any
     */
    void setCreator(U creator);

    /**
     * The developer working on this issue.
     *
     * @return any
     */
    U getAssignee();

    /**
     * Usually the current logged user. Implementations may limit updates on this field.
     *
     * @param assignee any
     */
    void setAssignee(U assignee);

    /**
     * The project that this issue targets.
     *
     * @return a not null project.
     */
    P getParentProject();

    /**
     * Establishes the project where this issue belongs. Implementations may limit updates on this field.
     *
     * @param project any
     */
    void setParentProject(P project);

    /**
     * The module or component this issue affects.
     *
     * @return a not null module
     */
    M getParentModule();

    /**
     * Establishes the module affected by this request.
     *
     * @param module any
     */
    void setParentModule(M module);

    /**
     * Title of the issue.
     *
     * @return a not empty String
     */
    String getSummary();

    /**
     * Sets the subject of this ticket.
     *
     * @param summary any (implementations may limit empty strings)
     */
    void setSummary(String summary);

    /**
     * The initial description provided by the user.
     *
     * @return any
     */
    String getDescription();

    /**
     * Sets the comments the user added when creating the issue for the first time.
     * Implementations may limit updates on this field.
     *
     * @param description any
     */
    void setDescription(String description);

    /**
     * Get the first detected version with the problem described here.
     *
     * @return a not null version
     */
    V getAffectedVersion();

    /**
     * Establish the version where this problem happens.
     *
     * @param version any
     */
    void setAffectedVersion(V version);

    /**
     * Gets the first released version that includes working code that fixes this issue.
     *
     * @return any
     */
    V getFixVersion();

    /**
     * Establish the version that will include a fix for this request.
     *
     * @param version any
     */
    void setFixVersion(V version);

    /**
     * Establish the version where this problem is expected to be resolved
     *
     * @param version any
     */
    void setTargetVersion(V version);

    /**
     * Retrieves the tags for this ticket.
     *
     * @return any
     */
    Collection<String> getTags();

    /**
     * Sets a group of tags.
     *
     * @param tags any
     */
    void setTags(Collection<String> tags);

    /**
     * The time when this issue was created.
     *
     * @return a not null date
     */
    Date getCreationDate();

    /**
     * Gets the importance of this issue.
     *
     * @return by default Severity.FIX
     */
    Severity getSeverity();

    /**
     * Sets the importance of this issue.
     *
     * @param severity a not null severity
     */
    void setSeverity(Severity severity);

    /**
     * Get the type of ticket.
     *
     * @return by default Type.BUG
     */
    Type getType();

    /**
     * Changes the type of request.
     *
     * @param type a not null type
     */
    void setType(Type type);

    /**
     * Gets current status. It'll allow/disallow different operations on this entity.
     *
     * @return by default, Status.OPEN
     */
    Status getStatus();

    /**
     * Changes current status. Implementations may limit the available transitions.
     *
     * @param status a not null status
     */
    void setStatus(Status status);

    /**
     * Obtains the final operational status.
     *
     * @return by default ResolutionStatus.PENDING
     */
    ResolutionStatus getResolutionStatus();

    /**
     * Changes final status. Implementations may limit the available transitions.
     *
     * @param resolutionStatus a not null resolution status
     */
    void setResolutionStatus(ResolutionStatus resolutionStatus);

    /**
     * A useful identifier when the primary key is too complex to use, for example, in URLs.
     *
     * @return a not null string
     */
    String getAlias();

    /**
     * Obtains the comments the developer included when closing this issue.
     *
     * @return any
     */
    String getResolutionComment();

    /**
     * Establish some comments from the developer when closing this issue
     *
     * @param comment any
     */
    void setResolutionComment(String comment);

    /**
     * Increments the vote count by one if the user hasn't already voted for this issue.
     *
     * @param user any
     * @return true if the vote was counted
     */
    boolean vote(U user);

    /**
     * Total number of votes this issue gathered.
     *
     * @return zero or a positive integer.
     */
    Integer getVotes();

    /**
     * Indicates the desire of a user to be notified of future events.
     *
     * @param user any
     * @return true if a new watch was added
     */
    boolean watch(U user);

    /**
     * Total number of watchers for this issue.
     *
     * @return a zero or positive integer
     */
    Integer getWatcherNumber();

    /**
     * Adds a new screenshot, patch or file in general to this issue.
     *
     * @param user the user who uploaded the doc
     * @param doc any
     */
    MultiDocument addAttachment(U user, Document doc);

    /**
     * Establish a relation between this issue an another one.
     *
     * @param user any
     * @param linkedIssue any
     * @param type any
     * @return null if the link was created, otherwise a validation problem
     */
    Errors link(U user, I linkedIssue, Link type);

    /**
     * Sets the status of this issue as closed with an optional resolution sttaus provided.
     *
     * @param user any
     * @param status any
     * @return true if the final status is closed
     */
    boolean close(U user, ResolutionStatus status);

    /**
     * Returns an ordered collection of comments.
     *
     * @return a non null non modifiable list
     */
    List<C> getCommentsByDate();

}
